local M = {}

local default_config = {
    display = {
        style = "minimal",
        max_height = 50, -- 小于0代表无限制
        max_width = 80,
        phnoetic = true,
        collins_star = true,
        oxford = true,
        wrap = true,
        border_style = "rounded",
        view = "cursor",
        offset_x = 2,
        offset_y = 2,
    },
    order = {
        "title",
        "zh",
        "pos",
        "exchange",
        "tag",
        -- "en",
    },

    db_path = "$HOME/.vim/dict/ultimate.db",

    icon = {
        star = "★",
        isOxford = "✔",
        notOxford = "",
    },
}

M.conf = default_config
M.db = require("sqlite.db")
M.buf = vim.api.nvim_create_buf(false, true)

local cfg_display = M.conf.display
local cfg_icon = M.conf.icon
local cfg_order = M.conf.order
local window = 0
local line = 0
local pos_info = {}

M.show_win = function(width, height)
    window = vim.api.nvim_open_win(M.buf, false, {
        relative = "cursor",
        title = " 翻译一下 ",
        title_pos = "center",
        style = cfg_display.style,
        col = cfg_display.offset_x,
        row = cfg_display.offset_y,
        width = (cfg_display.max_width > 0 and width > cfg_display.max_width) and cfg_display.max_width or width,
        height = (cfg_display.max_width > 0 and height > cfg_display.max_height) and cfg_display.max_height or height,
        border = cfg_display.border_style,
        focusable = true,
    })
    vim.api.nvim_set_option_value("wrap", cfg_display.wrap, { win = window })
end

-- NOTE: title
M.get_title = function(text, query_result)
    local title = string.format("%s    [%s]    ", query_result.word, query_result.phonetic)
        .. (cfg_display.oxford and (query_result.oxford == 1 and cfg_icon.isOxford .. "    " or cfg_icon.notOxford .. "    ") or "")
        .. (
            (cfg_display.collins_star and query_result.collins) and string.rep(cfg_icon.star, query_result.collins)
            or ""
        )
    table.insert(text, title)

    pos_info.title = {}
    pos_info.title.word_len = #query_result.word
    pos_info.title.phonetic_len = query_result.phonetic and #query_result.phonetic or 3
    pos_info.title.line = line
    line = line + 1
end

-- NOTE: tag
M.get_tag = function(text, query_result)
    if query_result.tag and #query_result.tag > 0 then
        local tag = query_result.tag
            :gsub("zk", "中考")
            :gsub("gk", "高考")
            :gsub("ky", "考研")
            :gsub("cet4", "四级")
            :gsub("cet6", "六级")
            :gsub("ielts", "雅思")
            :gsub("toefl", "托福")
            :gsub("gre", "GRE")
        table.insert(text, "标签:")
        table.insert(text, "    " .. tag)
        -- table.insert(text, "")

        pos_info.tag = line
        line = line + 3
    end
end

-- NOTE: pos 词性
M.get_pos = function(text, query_result)
    if query_result.pos and #query_result.pos > 0 then
        table.insert(text, "词性:")

        local content = 0
        for v in vim.gsplit(query_result.pos, [[/]]) do
            table.insert(text, string.format("    %s", v .. "%"))
            content = content + 1
        end

        table.insert(text, "")

        pos_info.pos = {}
        pos_info.pos.line = line
        pos_info.pos.content = content
        line = line + content + 2
    end
end

-- NOTE: exchange
M.get_exchange = function(text, query_result)
    if query_result.exchange and #query_result.exchange > 0 then
        table.insert(text, "词形变化:")

        local exchange_map = {
            p = "过去式",
            d = "过去分词",
            i = "现在分词",
            r = "形容词比较级",
            t = "形容词最高级",
            s = "名词复数形式",
            O = "词干",
            ["3"] = "第三人称单数",
        }

        local content = 0
        for v in vim.gsplit(query_result.exchange, [[/]]) do
            table.insert(text, string.format("    %s:  %s", exchange_map[v:sub(1, 1)], v:sub(3)))
            content = content + 1
            -- FIXME: 中文字符与字母位宽不一致, 暂时无法对齐
        end
        table.insert(text, "")

        pos_info.exchange = {}
        pos_info.exchange.line = line
        pos_info.exchange.content = content
        line = line + content + 2
    end
end

-- NOTE: 中文翻译
M.get_zh = function(text, query_result)
    if query_result.translation then
        table.insert(text, "中文翻译:")

        local content = 0
        for v in vim.gsplit(query_result.translation, "\n") do
            table.insert(text, "    " .. v)
            content = content + 1
        end
        table.insert(text, "")

        pos_info.zh = {}
        pos_info.zh.line = line
        pos_info.zh.content = content
        line = content + line + 2
    end
end

-- -- NOTE: 英文翻译
-- M.get_en = function(text, query_result)
--     if query_result.definition and #query_result.definition > 0 then
--         table.insert(text, "英文翻译:")
--
--         local content = 0
--         for v in vim.gsplit(query_result.definition, "\n") do
--             table.insert(text, "    " .. v)
--             content = content + 1
--         end
--         table.insert(text, "")
--
--         pos_info.en = {}
--         pos_info.en.line = line
--         pos_info.en.content = content
--         line = line + content + 2
--     end
-- end

local text_handlers = {
    title = M.get_title,
    tag = M.get_tag,
    pos = M.get_pos,
    exchange = M.get_exchange,
    zh = M.get_zh,
    -- en = M.get_en,
}

-- @return string array
M.get_text = function(query_result)
    if not query_result then
        return { "没有找到相关定义" }
    end
    local text = {}
    for _, v in ipairs(cfg_order) do
        text_handlers[v](text, query_result)
    end
    return text
end

M.set_text = function(lines)
    vim.api.nvim_buf_set_lines(M.buf, 0, -1, false, lines)
    local width = 0
    for _, v in ipairs(lines) do
        if #v > width then
            width = v:len()
        end
    end
    return width, #lines
end

-- title内容: 单词+音标+...
-- | TransWord |     [title.phonetic]     |
M.hl_title = function()
    vim.api.nvim_buf_add_highlight(M.buf, -1, "TransWord", pos_info.title.line, 0, pos_info.title.word_len)
    vim.api.nvim_buf_add_highlight(
        M.buf,
        -1,
        "TransPhonetic",
        pos_info.title.line,
        pos_info.title.word_len + 5,
        pos_info.title.word_len + 5 + pos_info.title.phonetic_len
    )
end

M.hl_tag = function()
    if pos_info.tag then
        vim.api.nvim_buf_add_highlight(M.buf, -1, "TransRef", pos_info.tag, 0, -1)
        vim.api.nvim_buf_add_highlight(M.buf, -1, "TransTag", pos_info.tag + 1, 0, -1)
    end
end

M.hl_pos = function()
    if pos_info.pos then
        vim.api.nvim_buf_add_highlight(M.buf, -1, "TransRef", pos_info.pos.line, 0, -1)
        for i = 1, pos_info.pos.content, 1 do
            vim.api.nvim_buf_add_highlight(M.buf, -1, "TransPos", pos_info.pos.line + i, 0, -1)
        end
    end
end

M.hl_exchange = function()
    if pos_info.exchange then
        vim.api.nvim_buf_add_highlight(M.buf, -1, "TransRef", pos_info.exchange.line, 0, -1)
        for i = 1, pos_info.exchange.content, 1 do
            vim.api.nvim_buf_add_highlight(M.buf, -1, "TransExchange", pos_info.exchange.line + i, 0, -1)
        end
    end
end

M.hl_zh = function()
    vim.api.nvim_buf_add_highlight(M.buf, -1, "TransRef", pos_info.zh.line, 0, -1)
    for i = 1, pos_info.zh.content, 1 do
        vim.api.nvim_buf_add_highlight(M.buf, -1, "TransZh", pos_info.zh.line + i, 0, -1)
    end
end

-- M.hl_en = function()
--     if pos_info.en then
--         vim.api.nvim_buf_add_highlight(M.buf, -1, "TransRef", pos_info.en.line, 0, -1)
--         for i = 1, pos_info.en.content, 1 do
--             vim.api.nvim_buf_add_highlight(M.buf, -1, "TransEN", pos_info.en.line + i, 0, -1)
--         end
--     end
-- end

local hl_handlers = {
    title = M.hl_title,
    tag = M.hl_tag,
    pos = M.hl_pos,
    exchange = M.hl_exchange,
    zh = M.hl_zh,
    -- en = M.hl_en,
}

M.set_highlight = function()
    for _, v in ipairs(cfg_order) do
        hl_handlers[v]()
    end
end

-- use vim.getregion() when available
M.get_visual_selection = function()
    -- 获取位置
    local s_start = vim.fn.getpos("'<")
    local s_end = vim.fn.getpos("'>")
    local n_lines = math.abs(s_end[2] - s_start[2]) + 1
    local lines = vim.api.nvim_buf_get_lines(0, s_start[2] - 1, s_end[2], false)
    lines[1] = string.sub(lines[1], s_start[3], -1)
    if n_lines == 1 then
        lines[n_lines] = string.sub(lines[n_lines], 1, s_end[3] - s_start[3] + 1)
    else
        lines[n_lines] = string.sub(lines[n_lines], 1, s_end[3])
    end
    -- return table.concat(lines, "\n")
    -- return table.concat(lines, " ")
    local res = table.concat(lines, " ")
    -- vim.print(res)
    return res

end

M.query = function(mode)
    assert(M.buf > 0)
    local word = ""
    if mode == "n" then
        word = vim.fn.expand("<cword>")
    elseif mode == "v" then
        word = M.get_visual_selection()
    else
        print(mode, "is invalid")
        assert(false)
    end

    local db_path = M.conf.db_path
    local dict = M.db:open(db_path)

    local do_query = function(arg)
        -- TODO: return type: a result table:
        local res = {}
        if type(arg) == "string" then
            res = dict:select("stardict", {
                where = { word = arg },
            })
        elseif type(arg) == "table" then
            res = dict:select("stardict", arg)
        else
            vim.notify("query argument error!")
        end
        return res[1]
    end

    local res = do_query(word)
    -- vim.notify(vim.inspect(res))
    -- 返回示例:
    -- {
    --   audio = "",
    --   bnc = 5665,
    --   collins = 1,
    --   definition = "v inform (somebody) of something",
    --   exchange = "d:notified/i:notifying/p:notified/3:notifies/s:notifies",
    --   frq = 6111,
    --   id = 2657730,
    --   phonetic = "ˈnəʊtɪfaɪ",
    --   pos = "v:100",
    --   sw = "notify",
    --   tag = "cet4 cet6 ky ielts",
    --   translation = "vt. 通告，通知；公布",
    --   word = "notify"
    -- }
    local text = M.get_text(res)
    local width, height = M.set_text(text)
    M.show_win(width, height)
    if res then
        M.set_highlight()
        local clear_tmp_info = function()
            pos_info = {}
            line = 0
        end
        clear_tmp_info()
    end
end

M.query_cursor = function()
    M.query("n")
end

M.query_select = function()
    M.query("v")
end

function M.close_win()
    if window > 0 then
        vim.api.nvim_win_close(window, true)
        window = 0
    end
end

-- 只需要执行一次且不需要启动就执行的部分(其实所有部分都可以往这放)
M.setup = function()
    vim.api.nvim_set_option_value("filetype", "Transs", { buf = M.buf })
    vim.api.nvim_create_user_command("TranslateCursorWord", M.query_cursor, {})
    vim.api.nvim_create_user_command("TranslateSelectWord", M.query_select, {})
    vim.api.nvim_create_user_command("TranslateClose", M.close_win, {})
    -- -- 创建buffer-local的用户命令
    -- -- FIXME: 按Esc时报错找不到命令
    -- vim.api.nvim_buf_create_user_command(M.buf, "TranslateClose", M.close_win, {})

    local group = vim.api.nvim_create_augroup("Trans", { clear = true })
    vim.api.nvim_create_autocmd("VimLeave", {
        group = group,
        pattern = "*",
        callback = function()
            if M.db:isopen() then
                M.db:close()
            end
        end,
    })
    vim.api.nvim_create_autocmd({ "InsertEnter", "CursorMoved", "BufLeave" }, {
        group = group,
        pattern = "*",
        callback = M.close_win,
    })

    vim.api.nvim_create_autocmd("FileType", {
        group = group,
        pattern = "*",
        command = "nnoremap <buffer><silent> <Esc> <Cmd>TranslateClose<CR>",
        -- -- 等价于:
        -- callback = function()
        --     -- vim.cmd.TranslateClose()
        --     vim.cmd([[
        --     nnoremap <buffer><silent> <Esc> <cmd>TranslateClose<CR>
        --     ]])
        -- end,
        -- -- 这样也不行
        -- callback = function()
        --     vim.api.nvim_buf_set_keymap(M.buf, "n", "<Esc>", "<cmd>TranslateClose<CR>", {})
        -- end,
    })

    -- Trans相关的高亮设置
    local set_hl_all = function()
        local set_hl = vim.api.nvim_set_hl
        set_hl(0, "TransWord", { fg = "#98c379", bold = true })
        set_hl(0, "TransPhonetic", { fg = "#8b949e" })
        set_hl(0, "TransRef", { fg = "#75beff", bold = true })
        set_hl(0, "TransTag", { fg = "#e5c07b" })
        set_hl(0, "TransPos", { link = "TransTag" })
        set_hl(0, "TransExchange", { link = "TransTag" })
        set_hl(0, "TransZh", { fg = "#7ee787" })
        set_hl(0, "TransEN", { fg = "#bc8cff" })
    end
    set_hl_all()
end

return M
